package com.dailyblue.java.design.单例模式;

import lombok.SneakyThrows;

import java.lang.reflect.Constructor;
import java.util.concurrent.atomic.AtomicReference;

public class App {
    private static void a() {
        DemoA a1 = DemoA.getInstance();
        DemoA a2 = DemoA.getInstance();
        System.out.println(a1);
        System.out.println(a2);
        System.out.println(a1 == a2);
    }

    private static void b() {
        DemoB b1 = DemoB.getInstance();
        DemoB b2 = DemoB.getInstance();
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b1 == b2);
    }

    @SneakyThrows
    private static void c() {
        AtomicReference<DemoB> b1 = new AtomicReference<>();
        AtomicReference<DemoB> b2 = new AtomicReference<>();
        Runnable r1 = () -> {
            b1.set(DemoB.getInstance());
        };
        Runnable r2 = () -> {
            b2.set(DemoB.getInstance());
        };
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(b1.get());
        System.out.println(b2.get());
        System.out.println(b1.get() == b2.get());
    }

    @SneakyThrows
    private static void d() {
        AtomicReference<DemoC> b1 = new AtomicReference<>();
        AtomicReference<DemoC> b2 = new AtomicReference<>();
        AtomicReference<DemoC> b3 = new AtomicReference<>();
        Runnable r1 = () -> {
            b1.set(DemoC.getInstance());
        };
        Runnable r2 = () -> {
            b2.set(DemoC.getInstance());
        };
        Runnable r3 = () -> {
            b3.set(DemoC.getInstance());
        };
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        Thread t3 = new Thread(r3);
        t1.start();
        Thread.sleep(3000);
        t2.start();
        Thread.sleep(3000);
        t3.start();
        t1.join();
        t2.join();
        t3.join();
        System.out.println(b1.get());
        System.out.println(b2.get());
        System.out.println(b3.get());
        System.out.println(b1.get() == b2.get());
    }

    // 问题：通过反射可以规避私有构造器的调用问题
    @SneakyThrows
    private static void e() {
        Class c = Class.forName("com.dailyblue.java.design.单例模式.DemoB");
        Constructor constructor = c.getDeclaredConstructor();
        // 可以访问私有属性、方法和构造器
        constructor.setAccessible(true);
        Object obj1 = constructor.newInstance();
        Object obj2 = constructor.newInstance();
        System.out.println(obj1);
        System.out.println(obj2);
        System.out.println(obj1 == obj2);
    }

    private static void f() {
        DemoD d1 = DemoD.INSTANCE;
        DemoD d2 = DemoD.INSTANCE;
        DemoD d3 = DemoD.INSTANCE;
        System.out.println(d1 == d2);
        System.out.println(d1 == d3);
        d1.a();
        d2.b();
    }

    public static void main(String[] args) {
        f();
    }
}
